package filters;

import draw.ExploringMedics;
import java.util.ArrayList;
import java.util.LinkedList;

public class SizeFilter {

    int imageDescription[][];
    ArrayList<Integer> sizes = new ArrayList<Integer>();
    ArrayList<Integer> xStart = new ArrayList<Integer>();
    ArrayList<Integer> yStart = new ArrayList<Integer>();
    ArrayList<Integer> xMinx = new ArrayList<Integer>();
    ArrayList<Integer> xMaxx = new ArrayList<Integer>();
    ArrayList<Integer> yMiny = new ArrayList<Integer>();
    ArrayList<Integer> yMaxy = new ArrayList<Integer>();
    int mask[][];
    int width = 0;
    int height = 0;
    int regionSize = 0;
    int smallSize = 10;
    public int minx = Integer.MAX_VALUE;
    public int miny = Integer.MAX_VALUE;
    public int maxx = 0;
    public int maxy = 0;

    public SizeFilter(int[][] imageDescription) {
        this.imageDescription = imageDescription;
        height = imageDescription[0].length;
        width = imageDescription.length;
        mask = new int[width][height];

        for (int i = 0; i < width; i++) {
            for (int j = 0; j < height; j++) {
                mask[i][j] = UNEXPLOR;
            }
        }

        doFilter();
    }
    private final int UNEXPLOR = -1;

    private void doFilter() {
        int mark = 0;
        for (int i = 0; i < width; i++) {
            for (int j = 0; j < height; j++) {
                regionSize = 0;
                if (imageDescription[i][j] == ExploringMedics.WHITE && mask[i][j] == UNEXPLOR) {
                    markConnectedComponent(i, j, mark, ExploringMedics.WHITE, mask);
                } else {
                    markConnectedComponent(i, j, mark, ExploringMedics.BLACK, mask);
                }
                sizes.add(regionSize);
                xStart.add(i);
                yStart.add(j);

                xMinx.add(minx);
                xMaxx.add(maxx);
                yMiny.add(miny);
                yMaxy.add(maxy);
            }
        }

        for (int i = 0; i < sizes.size(); i++) {
            if (sizes.get(i) < smallSize) {
                int x = xStart.get(i);
                int y = yStart.get(i);
                int color = imageDescription[x][y] == ExploringMedics.WHITE
                        ? ExploringMedics.BLACK : ExploringMedics.WHITE;
                
                for (int p = xMinx.get(i); p <= xMaxx.get(i); p++) {
                    for (int k = yMiny.get(i); k <= yMaxy.get(i); k++) {
                        if (mask[p][k] == mark) {
                            imageDescription[p][k] = color;
                        }
                    }
                }
            }
        }

    }

    void markConnectedComponent(int xPoint, int yPoint, int mark, int startColor, int mas[][]) {
        LinkedList<Integer> xQueue = new LinkedList<Integer>();
        LinkedList<Integer> yQueue = new LinkedList<Integer>();

        xQueue.push(xPoint);
        yQueue.push(yPoint);

        int dx[] = {-1, 1, 0, 0};
        int dy[] = {0, 0, -1, 1};

        regionSize = 0;
        minx = Integer.MAX_VALUE;
        miny = Integer.MAX_VALUE;
        maxx = 0;
        maxy = 0;


        while (!xQueue.isEmpty()) {
            int x = xQueue.pop();
            int y = yQueue.pop();

            if (x >= width || y >= height || x < 0 || y < 0) {
                continue;
            }

            if (imageDescription[x][y] == startColor && mas[x][y] == UNEXPLOR) {
                mas[x][y] = mark;

                regionSize++;

                minx = x < minx ? x : minx;
                miny = y < miny ? y : miny;
                maxx = x > maxx ? x : maxx;
                maxy = y > maxy ? y : maxy;

                for (int i = 0; i < 4; i++) {
                    xQueue.push(x + dx[i]);
                    yQueue.push(y + dy[i]);
                }
            }
        }
    }

    public int[][] getImageDescription() {
        return imageDescription;
    }

    public void setImageDescription(int[][] imageDescription) {
        this.imageDescription = imageDescription;
    }
}
